﻿// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
// Website: https://admin.blazor.zone

using ASY.Core;
using BootstrapBlazor.Components;
using BootstrapClient.DataAccess.Models;
using BootstrapClient.DataAccess.SqlSugar.Services;
using BootstrapClient.Web.Core;
using Furion.DatabaseAccessor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Configuration;
using System.Reflection;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// 
/// </summary>
public static class ServiceCollectionExtensions
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IServiceCollection AddSqlsugarDataAccessServices(this IServiceCollection services)
    {
        var configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>();

        var configs = new List<ConnectionConfig>
        {
            services.GetConnectionConfig("mssql", DbType.SqlServer),
            services.GetConnectionConfig("ba", DbType.Sqlite),
        };

        //多库注入
        var db = new SqlSugarClient(configs);
        services.TryAddSingleton<ISqlSugarClient>(db);

        //services.AddSqlSugar(c => c = services.GetConnectionConfig("ba", DbType.Sqlite));

        services.AddScoped(typeof(IDataService<>), typeof(DefaultDataService<>));


        //自动创建库和更新表
        InitcomDatabase(db);

        // 增加业务服务
        services.AddSingleton<IDict, DictService>();
        services.AddSingleton<INavigation, NavigationService>();
        services.AddSingleton<IUser, UserService>();

        // 增加示例数据服务
        services.AddSingleton<IDummy, DummyService>();
        return services;
    }


    public static ConnectionConfig GetConnectionConfig(this IServiceCollection services, string dbName, DbType dbType)
    {
        var configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>();
        var connString = configuration.GetConnectionString(dbName);
        return new ConnectionConfig
        {
            ConfigId = dbName,
            ConnectionString = connString,
            DbType = dbType,
            IsAutoCloseConnection = true,
            InitKeyType = InitKeyType.Attribute,
            ConfigureExternalServices = new ConfigureExternalServices()
            {
                EntityNameService = (type, entity) =>
                {
                    //表名称改动 //设置改动
                    if (type.GetCustomAttribute<TableAttribute>() is TableAttribute tableAttribute)
                    {
                        entity.DbTableName = tableAttribute.Name;
                    }
                    //增加表注释
                    if (type.GetCustomAttribute<DisplayAttribute>() is DisplayAttribute displayAttribute)
                    {
                        entity.TableDescription = displayAttribute.Name;
                    }

                    if (entity.DbTableName == nameof(User))
                    {
                        entity.DbTableName = "Users";
                    }
                    else if (entity.DbTableName == nameof(Dict))
                    {
                        entity.DbTableName = "Dicts";
                    }
                    else if (entity.DbTableName == nameof(Navigation))
                    {
                        entity.DbTableName = "Navigations";
                    }
                },
                EntityService = (type, column) =>
                {
                    //列名称改动 设置改动  
                    if (type.GetCustomAttribute<KeyAttribute>() is KeyAttribute keyAttribute)
                    {
                        //检查是否为key
                        column.IsPrimarykey = true;
                    }

                    if (type.GetCustomAttribute<DatabaseGeneratedAttribute>() is DatabaseGeneratedAttribute databaseGeneratedAttribute)
                    {
                        //检查是否为自增列
                        column.IsIdentity = databaseGeneratedAttribute.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity;
                    }
                    if (type.GetCustomAttribute<DisplayAttribute>() is DisplayAttribute displayAttribute)
                    {
                        column.ColumnDescription = displayAttribute.Name;
                    }
                    if (type.GetCustomAttribute<DisplayNameAttribute>() is DisplayNameAttribute displayNameAttribute)
                    {
                        column.ColumnDescription = displayNameAttribute.DisplayName;
                    }
                    if (type.GetCustomAttribute<NotMappedAttribute>() is NotMappedAttribute)
                    {
                        column.IsIgnore = true;
                    }
                    if (type.GetCustomAttribute<StringLengthAttribute>() is StringLengthAttribute lengthAttribute)
                    {
                        column.Length = lengthAttribute.MaximumLength;
                    }


                    //自动识别null
                    if (new NullabilityInfoContext().Create(type).WriteState is NullabilityState.Nullable)
                    {
                        column.IsNullable = true;
                    }

                    //字段名称为id自动改成 主键
                    if (column.DbColumnName.ToLower() == "id")
                    {
                        column.IsPrimarykey = true;
                    }
                }
            }
        };
    }

    /// <summary>
    /// 自动按照程序集 新建表 或者更新表
    /// </summary>
    /// <param name="db">ISqlSugarClient</param>
    /// <param name="stringDefaultLength">数据库字符串默认长度nvarchar(254) 默认 254</param>
    public static void InitcomDatabase(ISqlSugarClient db, int stringDefaultLength = 254)
    {
        //获取全部有效程序集
        var apptypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(t => t.GetTypes());

        var tabletypes = apptypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(TableAttribute), false)).ToArray();
        //指定当方法 (在当前方法加上这行，这个方法里面会生效)
        db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings()
        {
            DisableNvarchar = true,
            SqlServerCodeFirstNvarchar = true,
        };
        db.CodeFirst.SetStringDefaultLength(stringDefaultLength).InitTables(tabletypes);
    }

}

class DefaultDataService<TModel>(ISqlSugarClient db) : DataServiceBase<TModel> where TModel : class, new()
{
    /// <summary>
    /// 删除方法
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public override async Task<bool> DeleteAsync(IEnumerable<TModel> models)
    {
        // 通过模型获取主键列数据
        // 支持批量删除
        await db.Deleteable<TModel>(models).ExecuteCommandAsync();
        return true;
    }

    /// <summary>
    /// 保存方法
    /// </summary>
    /// <param name="model"></param>
    /// <param name="changedType"></param>
    /// <returns></returns>
    public override async Task<bool> SaveAsync(TModel model, ItemChangedType changedType)
    {
        await db.Storageable(model).ExecuteCommandAsync();
        return true;
    }

    /// <summary>
    /// 查询方法
    /// </summary>
    /// <param name="option"></param>
    /// <returns></returns>
    public override Task<QueryData<TModel>> QueryAsync(QueryPageOptions option)
    {
        int count = 0;

        var filter = option.ToFilter();

        var items = db.Queryable<TModel>()
            .WhereIF(filter.HasFilters(), filter.GetFilterLambda<TModel>())
            .OrderByIF(option.SortOrder != SortOrder.Unset, $" {option.SortName} {option.SortOrder}")
            .ToPageList(option.PageIndex, option.PageItems, ref count);

        var ret = new QueryData<TModel>()
        {
            TotalCount = count,
            Items = items,
            IsSorted = option.SortOrder != SortOrder.Unset,
            IsFiltered = option.Filters.Any(),
            IsAdvanceSearch = option.AdvanceSearches.Any(),
            IsSearch = option.Searches.Any() || option.CustomerSearches.Any()
        };
        return Task.FromResult(ret);
    }
}
